package asi.val;

import java.util.Hashtable;

/**
 * Collection of methods to convert special and extended
 * characters into HTML entitities and vice versa.<br/><br/>
 * Copyright (c) 2004-2005 Tecnick.com S.r.l (www.tecnick.com) Via Ugo Foscolo
 * n.19 - 09045 Quartu Sant'Elena (CA) - ITALY - www.tecnick.com -
 * info@tecnick.com<br/>
 * Project homepage: <a href="http://htmlentities.sourceforge.net" target="_blank">http://htmlentities.sourceforge.net</a><br/>
 * License: http://www.gnu.org/copyleft/lesser.html LGPL
 * @author Nicola Asuni [www.tecnick.com].
 * @version 1.0.004
 */
public class HTMLEntities {
	
	/**
	 * Translation table for HTML entities.<br/>
	 * reference: W3C - Character entity references in HTML 4 [<a href="http://www.w3.org/TR/html401/sgml/entities.html" target="_blank">http://www.w3.org/TR/html401/sgml/entities.html</a>].
	 */
	private final Object[][] html_entities_table = {
		{ new String("&Aacute;"), new Integer(193) },
		{ new String("&aacute;"), new Integer(225) },
		{ new String("&Acirc;"), new Integer(194) },
		{ new String("&acirc;"), new Integer(226) },
		{ new String("&acute;"), new Integer(180) },
		{ new String("&AElig;"), new Integer(198) },
		{ new String("&aelig;"), new Integer(230) },
		{ new String("&Agrave;"), new Integer(192) },
		{ new String("&agrave;"), new Integer(224) },
		{ new String("&alefsym;"), new Integer(8501) },
		{ new String("&Alpha;"), new Integer(913) },
		{ new String("&alpha;"), new Integer(945) },
		{ new String("&amp;"), new Integer(38) },
		{ new String("&and;"), new Integer(8743) },
		{ new String("&ang;"), new Integer(8736) },
		{ new String("&Aring;"), new Integer(197) },
		{ new String("&aring;"), new Integer(229) },
		{ new String("&asymp;"), new Integer(8776) },
		{ new String("&Atilde;"), new Integer(195) },
		{ new String("&atilde;"), new Integer(227) },
		{ new String("&Auml;"), new Integer(196) },
		{ new String("&auml;"), new Integer(228) },
		{ new String("&bdquo;"), new Integer(8222) },
		{ new String("&Beta;"), new Integer(914) },
		{ new String("&beta;"), new Integer(946) },
		{ new String("&brvbar;"), new Integer(166) },
		{ new String("&bull;"), new Integer(8226) },
		{ new String("&cap;"), new Integer(8745) },
		{ new String("&Ccedil;"), new Integer(199) },
		{ new String("&ccedil;"), new Integer(231) },
		{ new String("&cedil;"), new Integer(184) },
		{ new String("&cent;"), new Integer(162) },
		{ new String("&Chi;"), new Integer(935) },
		{ new String("&chi;"), new Integer(967) },
		{ new String("&circ;"), new Integer(710) },
		{ new String("&clubs;"), new Integer(9827) },
		{ new String("&cong;"), new Integer(8773) },
		{ new String("&copy;"), new Integer(169) },
		{ new String("&crarr;"), new Integer(8629) },
		{ new String("&cup;"), new Integer(8746) },
		{ new String("&curren;"), new Integer(164) },
		{ new String("&dagger;"), new Integer(8224) },
		{ new String("&Dagger;"), new Integer(8225) },
		{ new String("&darr;"), new Integer(8595) },
		{ new String("&dArr;"), new Integer(8659) },
		{ new String("&deg;"), new Integer(176) },
		{ new String("&Delta;"), new Integer(916) },
		{ new String("&delta;"), new Integer(948) },
		{ new String("&diams;"), new Integer(9830) },
		{ new String("&divide;"), new Integer(247) },
		{ new String("&Eacute;"), new Integer(201) },
		{ new String("&eacute;"), new Integer(233) },
		{ new String("&Ecirc;"), new Integer(202) },
		{ new String("&ecirc;"), new Integer(234) },
		{ new String("&Egrave;"), new Integer(200) },
		{ new String("&egrave;"), new Integer(232) },
		{ new String("&empty;"), new Integer(8709) },
		{ new String("&emsp;"), new Integer(8195) },
		{ new String("&ensp;"), new Integer(8194) },
		{ new String("&Epsilon;"), new Integer(917) },
		{ new String("&epsilon;"), new Integer(949) },
		{ new String("&equiv;"), new Integer(8801) },
		{ new String("&Eta;"), new Integer(919) },
		{ new String("&eta;"), new Integer(951) },
		{ new String("&ETH;"), new Integer(208) },
		{ new String("&eth;"), new Integer(240) },
		{ new String("&Euml;"), new Integer(203) },
		{ new String("&euml;"), new Integer(235) },
		{ new String("&euro;"), new Integer(8364) },
		{ new String("&exist;"), new Integer(8707) },
		{ new String("&fnof;"), new Integer(402) },
		{ new String("&forall;"), new Integer(8704) },
		{ new String("&frac12;"), new Integer(189) },
		{ new String("&frac14;"), new Integer(188) },
		{ new String("&frac34;"), new Integer(190) },
		{ new String("&frasl;"), new Integer(8260) },
		{ new String("&Gamma;"), new Integer(915) },
		{ new String("&gamma;"), new Integer(947) },
		{ new String("&ge;"), new Integer(8805) },
		{ new String("&harr;"), new Integer(8596) },
		{ new String("&hArr;"), new Integer(8660) },
		{ new String("&hearts;"), new Integer(9829) },
		{ new String("&hellip;"), new Integer(8230) },
		{ new String("&Iacute;"), new Integer(205) },
		{ new String("&iacute;"), new Integer(237) },
		{ new String("&Icirc;"), new Integer(206) },
		{ new String("&icirc;"), new Integer(238) },
		{ new String("&iexcl;"), new Integer(161) },
		{ new String("&Igrave;"), new Integer(204) },
		{ new String("&igrave;"), new Integer(236) },
		{ new String("&image;"), new Integer(8465) },
		{ new String("&infin;"), new Integer(8734) },
		{ new String("&int;"), new Integer(8747) },
		{ new String("&Iota;"), new Integer(921) },
		{ new String("&iota;"), new Integer(953) },
		{ new String("&iquest;"), new Integer(191) },
		{ new String("&isin;"), new Integer(8712) },
		{ new String("&Iuml;"), new Integer(207) },
		{ new String("&iuml;"), new Integer(239) },
		{ new String("&Kappa;"), new Integer(922) },
		{ new String("&kappa;"), new Integer(954) },
		{ new String("&Lambda;"), new Integer(923) },
		{ new String("&lambda;"), new Integer(955) },
		{ new String("&lang;"), new Integer(9001) },
		{ new String("&laquo;"), new Integer(171) },
		{ new String("&larr;"), new Integer(8592) },
		{ new String("&lArr;"), new Integer(8656) },
		{ new String("&lceil;"), new Integer(8968) },
		{ new String("&ldquo;"), new Integer(8220) },
		{ new String("&le;"), new Integer(8804) },
		{ new String("&lfloor;"), new Integer(8970) },
		{ new String("&lowast;"), new Integer(8727) },
		{ new String("&loz;"), new Integer(9674) },
		{ new String("&lrm;"), new Integer(8206) },
		{ new String("&lsaquo;"), new Integer(8249) },
		{ new String("&lsquo;"), new Integer(8216) },
		{ new String("&macr;"), new Integer(175) },
		{ new String("&mdash;"), new Integer(8212) },
		{ new String("&micro;"), new Integer(181) },
		{ new String("&middot;"), new Integer(183) },
		{ new String("&minus;"), new Integer(8722) },
		{ new String("&Mu;"), new Integer(924) },
		{ new String("&mu;"), new Integer(956) },
		{ new String("&nabla;"), new Integer(8711) },
		{ new String("&nbsp;"), new Integer(160) },
		{ new String("&ndash;"), new Integer(8211) },
		{ new String("&ne;"), new Integer(8800) },
		{ new String("&ni;"), new Integer(8715) },
		{ new String("&not;"), new Integer(172) },
		{ new String("&notin;"), new Integer(8713) },
		{ new String("&nsub;"), new Integer(8836) },
		{ new String("&Ntilde;"), new Integer(209) },
		{ new String("&ntilde;"), new Integer(241) },
		{ new String("&Nu;"), new Integer(925) },
		{ new String("&nu;"), new Integer(957) },
		{ new String("&Oacute;"), new Integer(211) },
		{ new String("&oacute;"), new Integer(243) },
		{ new String("&Ocirc;"), new Integer(212) },
		{ new String("&ocirc;"), new Integer(244) },
		{ new String("&OElig;"), new Integer(338) },
		{ new String("&oelig;"), new Integer(339) },
		{ new String("&Ograve;"), new Integer(210) },
		{ new String("&ograve;"), new Integer(242) },
		{ new String("&oline;"), new Integer(8254) },
		{ new String("&Omega;"), new Integer(937) },
		{ new String("&omega;"), new Integer(969) },
		{ new String("&Omicron;"), new Integer(927) },
		{ new String("&omicron;"), new Integer(959) },
		{ new String("&oplus;"), new Integer(8853) },
		{ new String("&or;"), new Integer(8744) },
		{ new String("&ordf;"), new Integer(170) },
		{ new String("&ordm;"), new Integer(186) },
		{ new String("&Oslash;"), new Integer(216) },
		{ new String("&oslash;"), new Integer(248) },
		{ new String("&Otilde;"), new Integer(213) },
		{ new String("&otilde;"), new Integer(245) },
		{ new String("&otimes;"), new Integer(8855) },
		{ new String("&Ouml;"), new Integer(214) },
		{ new String("&ouml;"), new Integer(246) },
		{ new String("&para;"), new Integer(182) },
		{ new String("&part;"), new Integer(8706) },
		{ new String("&permil;"), new Integer(8240) },
		{ new String("&perp;"), new Integer(8869) },
		{ new String("&Phi;"), new Integer(934) },
		{ new String("&phi;"), new Integer(966) },
		{ new String("&Pi;"), new Integer(928) },
		{ new String("&pi;"), new Integer(960) },
		{ new String("&piv;"), new Integer(982) },
		{ new String("&plusmn;"), new Integer(177) },
		{ new String("&pound;"), new Integer(163) },
		{ new String("&prime;"), new Integer(8242) },
		{ new String("&Prime;"), new Integer(8243) },
		{ new String("&prod;"), new Integer(8719) },
		{ new String("&prop;"), new Integer(8733) },
		{ new String("&Psi;"), new Integer(936) },
		{ new String("&psi;"), new Integer(968) },
		{ new String("&radic;"), new Integer(8730) },
		{ new String("&rang;"), new Integer(9002) },
		{ new String("&raquo;"), new Integer(187) },
		{ new String("&rarr;"), new Integer(8594) },
		{ new String("&rArr;"), new Integer(8658) },
		{ new String("&rceil;"), new Integer(8969) },
		{ new String("&rdquo;"), new Integer(8221) },
		{ new String("&real;"), new Integer(8476) },
		{ new String("&reg;"), new Integer(174) },
		{ new String("&rfloor;"), new Integer(8971) },
		{ new String("&Rho;"), new Integer(929) },
		{ new String("&rho;"), new Integer(961) },
		{ new String("&rlm;"), new Integer(8207) },
		{ new String("&rsaquo;"), new Integer(8250) },
		{ new String("&rsquo;"), new Integer(8217) },
		{ new String("&sbquo;"), new Integer(8218) },
		{ new String("&Scaron;"), new Integer(352) },
		{ new String("&scaron;"), new Integer(353) },
		{ new String("&sdot;"), new Integer(8901) },
		{ new String("&sect;"), new Integer(167) },
		{ new String("&shy;"), new Integer(173) },
		{ new String("&Sigma;"), new Integer(931) },
		{ new String("&sigma;"), new Integer(963) },
		{ new String("&sigmaf;"), new Integer(962) },
		{ new String("&sim;"), new Integer(8764) },
		{ new String("&spades;"), new Integer(9824) },
		{ new String("&sub;"), new Integer(8834) },
		{ new String("&sube;"), new Integer(8838) },
		{ new String("&sum;"), new Integer(8721) },
		{ new String("&sup1;"), new Integer(185) },
		{ new String("&sup2;"), new Integer(178) },
		{ new String("&sup3;"), new Integer(179) },
		{ new String("&sup;"), new Integer(8835) },
		{ new String("&supe;"), new Integer(8839) },
		{ new String("&szlig;"), new Integer(223) },
		{ new String("&Tau;"), new Integer(932) },
		{ new String("&tau;"), new Integer(964) },
		{ new String("&there4;"), new Integer(8756) },
		{ new String("&Theta;"), new Integer(920) },
		{ new String("&theta;"), new Integer(952) },
		{ new String("&thetasym;"), new Integer(977) },
		{ new String("&thinsp;"), new Integer(8201) },
		{ new String("&THORN;"), new Integer(222) },
		{ new String("&thorn;"), new Integer(254) },
		{ new String("&tilde;"), new Integer(732) },
		{ new String("&times;"), new Integer(215) },
		{ new String("&trade;"), new Integer(8482) },
		{ new String("&Uacute;"), new Integer(218) },
		{ new String("&uacute;"), new Integer(250) },
		{ new String("&uarr;"), new Integer(8593) },
		{ new String("&uArr;"), new Integer(8657) },
		{ new String("&Ucirc;"), new Integer(219) },
		{ new String("&ucirc;"), new Integer(251) },
		{ new String("&Ugrave;"), new Integer(217) },
		{ new String("&ugrave;"), new Integer(249) },
		{ new String("&uml;"), new Integer(168) },
		{ new String("&upsih;"), new Integer(978) },
		{ new String("&Upsilon;"), new Integer(933) },
		{ new String("&upsilon;"), new Integer(965) },
		{ new String("&Uuml;"), new Integer(220) },
		{ new String("&uuml;"), new Integer(252) },
		{ new String("&weierp;"), new Integer(8472) },
		{ new String("&Xi;"), new Integer(926) },
		{ new String("&xi;"), new Integer(958) },
		{ new String("&Yacute;"), new Integer(221) },
		{ new String("&yacute;"), new Integer(253) },
		{ new String("&yen;"), new Integer(165) },
		{ new String("&yuml;"), new Integer(255) },
		{ new String("&Yuml;"), new Integer(376) },
		{ new String("&Zeta;"), new Integer(918) },
		{ new String("&zeta;"), new Integer(950) },
		{ new String("&zwj;"), new Integer(8205) },
		{ new String("&zwnj;"), new Integer(8204) } };
	
	/**
	 * Map to convert extended characters in html entities.
	 */
	private final Hashtable htmlentities_map = new Hashtable();
	
	/**
	 * Map to convert html entities in exteden characters.
	 */
	private final Hashtable unhtmlentities_map = new Hashtable();
	
	//==============================================================================
	// METHODS
	//==============================================================================
	
	/**
	 * Initialize HTML translation maps.
	 */
	public HTMLEntities() {
		initializeEntitiesTables();
	}
	
	/**
	 * Initialize HTML entities table.
	 */
	private void initializeEntitiesTables() {
		// initialize html translation maps
		for (int i = 0; i < html_entities_table.length; ++i) {
			htmlentities_map.put(html_entities_table[i][1],
					html_entities_table[i][0]);
			unhtmlentities_map.put(html_entities_table[i][0],
					html_entities_table[i][1]);
		}
	}
	
	/**
	 * Get the html entities translation table.
	 * 
	 * @return translation table
	 */
	public Object[][] getEntitiesTable() {
		return html_entities_table;
	}
	
	/**
	 * Convert special and extended characters into HTML entitities.
	 * @param str input string
	 * @return formatted string
	 * @see #unhtmlentities(String)
	 */
	public String htmlentities(String str) {
		
		if (str == null) {
			return "";
		}
		//initialize html translation maps table the first time is called
		if (htmlentities_map.isEmpty()) {
			initializeEntitiesTables();
		}
		
		StringBuffer buf = new StringBuffer(); //the otput string buffer
		
		for (int i = 0; i < str.length(); ++i) {
			char ch = str.charAt(i);
			String entity = (String) htmlentities_map.get(new Integer((int) ch)); //get equivalent html entity
			if (entity == null) { //if entity has not been found
				if (((int) ch) > 128) { //check if is an extended character
					buf.append("&#" + ((int) ch) + ";"); //convert extended character
				} else {
					buf.append(ch); //append the character as is
				}
			} else {
				buf.append(entity); //append the html entity
			}
		}
		return buf.toString();
	}
	
	/**
	 * Convert HTML entities to special and extended unicode characters
	 * equivalents.
	 * @param str input string
	 * @return formatted string
	 * @see #htmlentities(String)
	 */
	public String unhtmlentities(String str) {
		
		//initialize html translation maps table the first time is called
		if (htmlentities_map.isEmpty()) {
			initializeEntitiesTables();
		}
		
		StringBuffer buf = new StringBuffer();
		
		for (int i = 0; i < str.length(); ++i) {
			char ch = str.charAt(i);
			if (ch == '&') {
				int semi = str.indexOf(';', i + 1);
				if ((semi == -1) || ((semi-i) > 7)){
					buf.append(ch);
					continue;
				}
				String entity = str.substring(i, semi + 1);
				Integer iso;
				if (entity.charAt(1) == ' ') {
					buf.append(ch);
					continue;
				}
				if (entity.charAt(1) == '#') {
					if (entity.charAt(2) == 'x') {
						iso = new Integer(Integer.parseInt(entity.substring(3, entity.length() - 1), 16));
					}
					else {
						iso = new Integer(entity.substring(2, entity.length() - 1));
					}
				} else {
					iso = (Integer) unhtmlentities_map.get(entity);
				}
				if (iso == null) {
					buf.append(entity);
				} else {
					buf.append((char) (iso.intValue()));
				}
				i = semi;
			} else {
				buf.append(ch);
			}
		}
		String ok = this.unhtmlQuotes(buf.toString());
		ok = this.unhtmlAmpersand(ok);
		return ok;
	}
	
	// methods to convert special characters
	
	/**
	 * Replace single quotes characters with HTML entities.
	 * 
	 * @param str the input string
	 * @return string with replaced single quotes
	 */
	public String htmlSingleQuotes(String str) {
		str = str.replaceAll("[\']", "&rsquo;");
		str = str.replaceAll("&#039;", "&rsquo;");
		str = str.replaceAll("&#145;", "&rsquo;");
		str = str.replaceAll("&#146;", "&rsquo;");
		return str;
	}
	
	/**
	 * Replace single quotes HTML entities with equivalent character.
	 * 
	 * @param str the input string
	 * @return string with replaced single quotes
	 */
	public String unhtmlSingleQuotes(String str) {
		return str.replaceAll("&rsquo;", "\'");
	}
	
	/**
	 * Replace double quotes characters with HTML entities.
	 * 
	 * @param str the input string
	 * @return string with replaced double quotes
	 */
	public String htmlDoubleQuotes(String str) {
		str = str.replaceAll("[\"]", "&quot;");
		str = str.replaceAll("&#147;", "&quot;");
		str = str.replaceAll("&#148;", "&quot;");
		return str;
	}
	
	/**
	 * Replace single quotes HTML entities with equivalent character.
	 * 
	 * @param str the input string
	 * @return string with replaced single quotes
	 */
	public String unhtmlDoubleQuotes(String str) {
		return str.replaceAll("&quot;", "\"");
	}
	
	/**
	 * Replace single and double quotes characters with HTML entities.
	 * 
	 * @param str the input string
	 * @return string with replaced quotes
	 */
	public String htmlQuotes(String str) {
		str = htmlDoubleQuotes(str); //convert double quotes
		str = htmlSingleQuotes(str); //convert single quotes
		return str;
	}
	
	/**
	 * Replace single and double quotes HTML entities with equivalent characters.
	 * 
	 * @param str the input string
	 * @return string with replaced quotes
	 */
	public String unhtmlQuotes(String str) {
		str = unhtmlDoubleQuotes(str); //convert double quotes
		str = unhtmlSingleQuotes(str); //convert single quotes
		return str;
	}
	
	/**
	 * Replace &lt; &gt; characters with &amp;lt; &amp;gt; entities.
	 * 
	 * @param str the input string
	 * @return string with replaced characters
	 */
	public String htmlAngleBrackets(String str) {
		str = str.replaceAll("<", "&lt;");
		str = str.replaceAll(">", "&gt;");
		return str;
	}
	
	/**
	 * Replace &amp;lt; &amp;gt; entities with &lt; &gt; characters.
	 * 
	 * @param str the input string
	 * @return string with replaced entities
	 */
	public String unhtmlAngleBrackets(String str) {
		str = str.replaceAll("&lt;", "<");
		str = str.replaceAll("&gt;", ">");
		return str;
	}
	
	/**
	 * Replace &amp; characters with &amp;amp; HTML entities.
	 * 
	 * @param str the input string
	 * @return string with replaced characters
	 */
	public String htmlAmpersand(String str) {
		return str.replaceAll("&", "&amp;");
	}
	
	/**
	 * Replace &amp;amp; HTML entities with &amp; characters.
	 * 
	 * @param str the input string
	 * @return string with replaced entities
	 */
	public String unhtmlAmpersand(String str) {
		return str.replaceAll("&amp;", "&");
	}
	
}